package org.example.zuul.web;

import java.util.Collection;

import javax.servlet.http.HttpServletRequest;

import org.example.zuul.filter.ZuulProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.RequestPath;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;

@Component
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {
    private static final Logger LOGGER = LoggerFactory.getLogger(ZuulHandlerMapping.class);
    private final ZuulController zuulController;
    private final Collection<ZuulProperties.ZuulRoute> routes;
    private boolean inited = false;

    public ZuulHandlerMapping(ZuulProperties zuulProperties, ZuulController zuulController) {
        this.routes = zuulProperties.getRoutes().values();
        this.zuulController = zuulController;
        setOrder(-200);
    }

    @Override
    protected HandlerExecutionChain getCorsHandlerExecutionChain(
            HttpServletRequest request, HandlerExecutionChain chain,
            CorsConfiguration config) {
        if (config == null) {
            // Allow CORS requests to go to the backend
            return chain;
        }
        return super.getCorsHandlerExecutionChain(request, chain, config);
    }

    @Override
    protected Object lookupHandler(RequestPath path, String lookupPath, HttpServletRequest request) throws Exception {
        return super.lookupHandler(path, lookupPath, request);
    }

    @Override
    protected Object lookupHandler(String lookupPath, HttpServletRequest request) throws Exception {
        if (!inited) {
            synchronized (this) {
                if (!inited) {
                    registerHandlers();
                    inited = true;
                }
            }
        }
        return super.lookupHandler(lookupPath, request);
    }

    private void registerHandlers() {
        if (routes.isEmpty()) {
            LOGGER.warn("No routes found from RouteLocator");
        } else {
            for (ZuulProperties.ZuulRoute route : routes) {
                registerHandler(route.getPath(), this.zuulController);
            }
        }
    }
}
